package main

import (
	"crypto/md5"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"net/url"
	"sort"

	"github.com/ying32/govcl/vcl"
	"github.com/ying32/govcl/vcl/types"
)

// 创建转换页面
func (f *MainForm) createDevelopFrame(i int) {
	// 创建容器
	f.contentFrame[i] = vcl.NewFrame(f)
	f.contentFrame[i].SetParent(f)
	f.contentFrame[i].SetAlign(types.AlClient)
	f.contentFrame[i].SetColor(contentColor)

	var top int32 = commonPadding

	f.developFrame.jsonViewer = vcl.NewButton(f)
	f.developFrame.jsonViewer.SetParent(f.contentFrame[i])
	f.developFrame.jsonViewer.SetBounds(commonPadding, top, formButtonWidth, formItemHeight)
	f.developFrame.jsonViewer.SetCaption("JSON视图")
	f.developFrame.jsonViewer.SetOnClick(func(sender vcl.IObject) {
		// 原生实现
		f.openJsonViewer()
	})

	top += commonPadding + formItemHeight
	f.developFrame.codeConversion = vcl.NewButton(f)
	f.developFrame.codeConversion.SetParent(f.contentFrame[i])
	f.developFrame.codeConversion.SetBounds(commonPadding, top, formButtonWidth, formItemHeight)
	f.developFrame.codeConversion.SetCaption("编码转换")
	f.developFrame.codeConversion.SetOnClick(func(sender vcl.IObject) {
		f.openCodeConversion()
	})

	top += commonPadding + formItemHeight
	f.developFrame.formatConversion = vcl.NewButton(f)
	f.developFrame.formatConversion.SetParent(f.contentFrame[i])
	f.developFrame.formatConversion.SetBounds(commonPadding, top, formButtonWidth, formItemHeight)
	f.developFrame.formatConversion.SetCaption("格式转换")
	f.developFrame.formatConversion.SetOnClick(func(sender vcl.IObject) {

	})
}

func (f *MainForm) buildJsonViewer(jsonTree *vcl.TTreeView, node *vcl.TTreeNode, data interface{}, keyName string) {
	switch data.(type) {
	case map[string]interface{}:
		var (
			child   *vcl.TTreeNode
			dataMap = data.(map[string]interface{})
		)
		if keyName != "" {
			child = jsonTree.Items().AddChild(node, keyName)
			child = jsonTree.Items().AddChild(child, " Object ")
		} else {
			child = jsonTree.Items().AddChild(node, " Object ")
		}
		keys := make([]string, 0)
		for key := range dataMap {
			keys = append(keys, key)
		}
		sort.Strings(keys)
		for _, key := range keys {
			if val, ok := data.(map[string]interface{})[key]; ok {
				f.buildJsonViewer(jsonTree, child, val, key)
			}
		}
	case []interface{}:
		var (
			child *vcl.TTreeNode
			list  = data.([]interface{})
		)
		if keyName != "" {
			child = jsonTree.Items().AddChild(node, keyName)
			child = jsonTree.Items().AddChild(child, fmt.Sprintf(" Array [%d] ", len(list)))
		} else {
			child = jsonTree.Items().AddChild(node, fmt.Sprintf(" Array [%d] ", len(list)))
		}
		for _, val := range list {
			f.buildJsonViewer(jsonTree, child, val, "")
		}
	default:
		if node != nil && node.IsValid() {
			if keyName == "" {
				jsonTree.Items().AddChild(node, fmt.Sprintf(" %v ", data))
			} else {
				jsonTree.Items().AddChild(node, fmt.Sprintf(" %s:  %v ", keyName, data))
			}
		}
	}
}

func (f *MainForm) openJsonViewer() {
	var (
		jsonStr  *vcl.TMemo
		jsonTree *vcl.TTreeView
	)

	jsonViewer := vcl.NewForm(f)
	jsonViewer.SetPosition(types.PoMainFormCenter)
	jsonViewer.SetWidth(width * 2)
	jsonViewer.SetHeight(height * 2)
	jsonViewer.SetCaption("Json视图")

	var top int32 = commonPadding
	hiddenStr := vcl.NewButton(f)
	hiddenStr.SetParent(jsonViewer)
	hiddenStr.SetBounds(commonPadding, top, formButtonWidth, formItemHeight)
	hiddenStr.SetCaption("隐藏原始字符串")
	hiddenStr.SetOnClick(func(sender vcl.IObject) {
		if jsonStr.Visible() {
			jsonStr.SetVisible(false)
			jsonTree.SetLeft(commonPadding)
			jsonTree.SetWidth(jsonViewer.Width() - commonPadding*2)
			hiddenStr.SetCaption("显示原始字符串")
		} else {
			jsonStr.SetVisible(true)
			newWidth := (jsonViewer.Width() - commonPadding*3) / 2
			newHeight := jsonViewer.Height() - top - commonPadding
			jsonStr.SetWidth(newWidth)
			jsonStr.SetHeight(newHeight)
			jsonTree.SetLeft(jsonViewer.Width() - newWidth - commonPadding)
			jsonTree.SetWidth(newWidth)
			jsonTree.SetHeight(newHeight)
			hiddenStr.SetCaption("隐藏原始字符串")
		}
	})

	changeNode := vcl.NewButton(f)
	changeNode.SetParent(jsonViewer)
	changeNode.SetBounds(hiddenStr.Left()+hiddenStr.Width()+commonPadding, top, formButtonWidth, formItemHeight)
	changeNode.SetCaption("折叠所有节点")
	changeNode.SetOnClick(func(sender vcl.IObject) {
		if changeNode.Caption() == "折叠所有节点" {
			jsonTree.FullCollapse()
			changeNode.SetCaption("展开所有节点")
		} else {
			jsonTree.FullExpand()
			changeNode.SetCaption("折叠所有节点")
		}
	})

	transform := vcl.NewButton(f)
	transform.SetParent(jsonViewer)
	transform.SetBounds(changeNode.Left()+changeNode.Width()+commonPadding, top, formButtonWidth, formItemHeight)
	transform.SetCaption("转换")
	transform.SetOnClick(func(sender vcl.IObject) {
		jsonTree.Items().Clear()
		var data interface{}
		if err := json.Unmarshal([]byte(jsonStr.Text()), &data); err != nil {
			vcl.ShowMessage(err.Error())
			return
		}
		jsonStr.SetText(formatJson(jsonStr.Text()))
		jsonTree.Items().BeginUpdate()
		defer jsonTree.Items().EndUpdate()
		f.buildJsonViewer(jsonTree, nil, data, "")
		jsonTree.FullExpand()
		changeNode.SetCaption("折叠所有节点")
	})

	top += commonPadding + formItemHeight
	memoWidth := (jsonViewer.Width() - commonPadding*3) / 2
	memoHeight := jsonViewer.Height() - top - commonPadding
	jsonStr = vcl.NewMemo(f)
	jsonStr.SetParent(jsonViewer)
	jsonStr.SetScrollBars(types.SsAutoVertical)
	jsonStr.SetBounds(commonPadding, top, memoWidth, memoHeight)

	jsonTree = vcl.NewTreeView(f)
	jsonTree.SetParent(jsonViewer)
	jsonTree.SetExpandSignType(types.TvestPlusMinus)
	jsonTree.SetSelectionColor(0x0041362F)
	jsonTree.SetBounds(jsonViewer.Width()-jsonStr.Width()-commonPadding, top, memoWidth, memoHeight)

	jsonViewer.Show()
	jsonViewer.SetOnResize(func(sender vcl.IObject) {
		if jsonStr.Visible() {
			newWidth := (jsonViewer.Width() - commonPadding*3) / 2
			newHeight := jsonViewer.Height() - top - commonPadding

			jsonStr.SetWidth(newWidth)
			jsonStr.SetHeight(newHeight)

			jsonTree.SetLeft(jsonViewer.Width() - newWidth - commonPadding)
			jsonTree.SetWidth(newWidth)
			jsonTree.SetHeight(newHeight)
		} else {
			jsonTree.SetLeft(commonPadding)
			jsonTree.SetWidth(jsonViewer.Width() - commonPadding*2)
			jsonTree.SetHeight(jsonViewer.Height() - top - commonPadding)
		}
	})
	jsonViewer.SetOnClose(func(sender vcl.IObject, action *types.TCloseAction) {
		f.BringToFront()
	})
}

func (f *MainForm) openCodeConversion() {
	var (
		input  *vcl.TMemo
		output *vcl.TMemo
	)

	codeConversion := vcl.NewForm(f)
	codeConversion.SetPosition(types.PoMainFormCenter)
	codeConversion.SetWidth(width * 1.5)
	codeConversion.SetHeight(height * 1.5)
	codeConversion.SetCaption("编码转换")

	var top int32 = commonPadding
	typeList := vcl.NewComboBox(f)
	typeList.SetParent(codeConversion)
	typeList.SetBounds(commonPadding, top, formEditWidth, empty)
	typeList.SetStyle(types.CsDropDownList)
	typeList.Items().Add("MD5")
	typeList.Items().Add("Base64")
	typeList.Items().Add("URL")

	encode := vcl.NewButton(f)
	encode.SetParent(codeConversion)
	encode.SetBounds(typeList.Left()+typeList.Width()+commonPadding, top, formButtonWidth, formItemHeight)
	encode.SetCaption("编码")
	encode.SetOnClick(func(sender vcl.IObject) {
		output.Clear()
		switch typeList.ItemIndex() {
		case 0:
			md5h := md5.New()
			md5h.Write([]byte(input.Text()))
			output.SetText(hex.EncodeToString(md5h.Sum(nil)))
		case 1:
			output.SetText(base64.StdEncoding.EncodeToString([]byte(input.Text())))
		case 2:
			output.SetText(url.QueryEscape(input.Text()))
		default:
			break
		}
	})

	decode := vcl.NewButton(f)
	decode.SetParent(codeConversion)
	decode.SetBounds(encode.Left()+encode.Width()+commonPadding, top, formButtonWidth, formItemHeight)
	decode.SetCaption("解码")
	decode.SetOnClick(func(sender vcl.IObject) {
		input.Clear()
		switch typeList.ItemIndex() {
		case 1:
			if decodeBytes, err := base64.StdEncoding.DecodeString(output.Text()); err != nil {
				input.SetText(err.Error())
			} else {
				input.SetText(string(decodeBytes))
			}
		case 2:
			if unescape, err := url.QueryUnescape(output.Text()); err != nil {
				input.SetText(err.Error())
			} else {
				input.SetText(unescape)
			}
		case 0:
		default:
			break
		}
	})

	top += commonPadding + formItemHeight
	memoWidth := (codeConversion.Width() - commonPadding*3) / 2
	memoHeight := codeConversion.Height() - top - commonPadding
	input = vcl.NewMemo(f)
	input.SetParent(codeConversion)
	input.SetBounds(commonPadding, top, memoWidth, memoHeight)

	output = vcl.NewMemo(f)
	output.SetParent(codeConversion)
	output.SetBounds(codeConversion.Width()-input.Width()-commonPadding, top, memoWidth, memoHeight)

	codeConversion.Show()
	codeConversion.SetOnResize(func(sender vcl.IObject) {
		memoWidth := (codeConversion.Width() - commonPadding*3) / 2
		memoHeight := codeConversion.Height() - top - commonPadding

		input.SetWidth(memoWidth)
		input.SetHeight(memoHeight)

		output.SetLeft(codeConversion.Width() - input.Width() - commonPadding)
		output.SetWidth(memoWidth)
		output.SetHeight(memoHeight)
	})
	codeConversion.SetOnClose(func(sender vcl.IObject, action *types.TCloseAction) {
		f.BringToFront()
	})
}
